import { UserFriendlyException } from "@/exceptions/IUserFriendlyException";
import { LocalUser } from "@/users";
import axios from "axios";
import type { AxiosRequestConfig } from "axios";

class HttpClient {
  private handleError(error: unknown) {
    if (axios.isAxiosError(error)) {
      // 有服务器响应的情况（4xx/5xx）
      const status = error.response?.status || 500;
      // http 请求会将错误封装在 error 对象中
      const message = error.response?.data?.error?.message || error.message;

      // 特殊状态码处理（如401跳转登录）
      if (status === 401) {
        return UserFriendlyException.createDefaultException("操作未授权！");
      }

      return UserFriendlyException.createException(
        message,
        status.toString(),
        error
      );
    } else {
      // 无服务器响应的情况（网络错误/超时）
      return UserFriendlyException.createException(
        "网络连接异常，请检查网络设置！",
        "NETWORK_ERROR",
        error!
      );
    }
  }

  public async getAsync<TResult>(url: string, requiresAuth: boolean = true) {
    const request: AxiosRequestConfig = {
      url: url,
      baseURL: url,
      method: "get",
      headers: {
        "Content-Type": "application/json",
      },
      transformResponse: (data) => {
        try {
          return JSON.parse(data);
        } catch {
          return null;
        }
      }, // 统一转换逻辑[5](@ref)
    };

    try {
      if (requiresAuth) {
        const userInfo = LocalUser.tryGetUserInfo();
        if (userInfo == null) {
          throw new UserFriendlyException("用户未登录！");
        }
        request.headers!.Authorization = userInfo.getAccessToken();
        const response = await axios.request(request);
        return response.data as TResult;
      } else {
        const response = await axios.request(request);
        return response.data as TResult;
      }
    } catch (error) {
      // 统一错误处理入口
      throw this.handleError(error);
    }
  }

  public async actionAsync(
    url: string,
    data: object,
    requiresAuth: boolean = true
  ) {
    const request: AxiosRequestConfig = {
      url: url,
      method: "post",
      headers: {
        "Content-Type": "application/json",
      },
      data: JSON.stringify(data),
    };
    try {
      if (requiresAuth) {
        const userInfo = LocalUser.tryGetUserInfo();
        if (userInfo == null) {
          throw new UserFriendlyException("用户未登录！");
        }
        request.headers!.Authorization = userInfo.getAccessToken();
        await axios.request(request);
      } else {
        await axios.request(request);
      }
    } catch (error) {
      // 统一错误处理入口
      throw this.handleError(error);
    }
  }

  // 插入或更新对象操作请求
  private async actionObjectRequestAsync<TResult>(
    method: string,
    url: string,
    data: object,
    requiresAuth: boolean = true
  ) {
    const request: AxiosRequestConfig = {
      url: url,
      method: method,
      headers: {
        "Content-Type": "application/json",
      },
      data: JSON.stringify(data),
      transformResponse: (data) => {
        try {
          return JSON.parse(data);
        } catch {
          return null;
        }
      }, // 统一转换逻辑[5](@ref)
    };
    try {
      if (requiresAuth) {
        const userInfo = LocalUser.tryGetUserInfo();
        if (userInfo == null) {
          throw new UserFriendlyException("用户未登录！");
        }
        request.headers!.Authorization = userInfo.getAccessToken();
        const response = await axios.request(request);
        return response.data as TResult;
      } else {
        const response = await axios.request(request);
        return response.data as TResult;
      }
    } catch (error) {
      // 统一错误处理入口
      throw this.handleError(error);
    }
  }

  // 插入对象请求
  public async insertAsync<TResult>(
    url: string,
    data: object,
    requiresAuth: boolean = true
  ) {
    return await this.actionObjectRequestAsync<TResult>(
      "post",
      url,
      data,
      requiresAuth
    );
  }

  // 更新对象请求
  public async updateAsync<TResult>(
    url: string,
    data: object,
    requiresAuth: boolean = true
  ) {
    return await this.actionObjectRequestAsync<TResult>(
      "put",
      url,
      data,
      requiresAuth
    );
  }
}

export { HttpClient };
